using System;

namespace RapidHDL
{
	/// <summary>
	/// Summary description for TruthTableComponent.
	/// </summary>
	public class TruthTableComponent : Component
	{
		TruthTable oTruthTable;

		public TruthTableComponent(Component poParentComponent, string psName) 
			: base (poParentComponent,psName)
		{
		}
	
		protected void GetTruthTable(string psTruthTableName, int piInputWidth, int piOutputWidth)
		{
			string sTruthTableName = psTruthTableName + "_" + piInputWidth.ToString() + "_" + piOutputWidth.ToString();
			oTruthTable = this.RapidHardware.Structure.TruthTableCoordinator.GetTruthTable(sTruthTableName);
			if (oTruthTable == null)
			{
				oTruthTable = new TruthTable(piInputWidth,piOutputWidth,sTruthTableName);
				GenerateTruthTable();
			}
		}

		protected virtual void GenerateTruthTable()
		{
		}

		protected TruthTable TruthTable
		{
			get{return oTruthTable;}
		}

		public void WriteVerilogLookupTable()
		{
			string sVerilog = "";
			string sOutputVector = "";
			string sOutput = "";

			ComponentVerilog.VerilogTraceLog("Starting To Write Lookup Table");
           

			foreach(NodeVector oNodeVector in this.SourceNodeVectors.Values)
			{
                if (oNodeVector.Width == 1)
                    ComponentVerilog.WriteVerilogText("reg " + oNodeVector.Name + ";", 3);
                else
                {
                    int iStart = oNodeVector.Width - 1;
                    ComponentVerilog.WriteVerilogText("reg [" + iStart.ToString() + ":0] " + oNodeVector.Name + ";", 3);
                }
			}
			ComponentVerilog.WriteVerilogSkip(); 


			sVerilog = "always @(";
			foreach(NodeVector oNodeVector in this.SinkNodeVectors.Values)
			{
				sVerilog += oNodeVector.Name + " or ";
			}
			sVerilog = sVerilog.Remove(sVerilog.Length - 4,4) + ")";
			
			ComponentVerilog.WriteVerilogText(sVerilog);
			ComponentVerilog.WriteVerilogText("begin");

			sVerilog = "case ({";
			foreach(NodeVector oNodeVector in this.SinkNodeVectors.Values)
			{
				sVerilog += oNodeVector.Name + ",";
			}
			sVerilog = sVerilog.Remove(sVerilog.Length - 1,1) + "})";
			ComponentVerilog.WriteVerilogText(sVerilog,1);

			sOutputVector = "{";
			foreach(NodeVector oNodeVector in this.SourceNodeVectors.Values)
			{
				sOutputVector += oNodeVector.Name + ",";
			}
			sOutputVector = sOutputVector.Remove(sOutputVector.Length - 1,1) + "}";


			foreach(string sInputKey in oTruthTable.TruthTableDefinition.Keys)
			{
				sVerilog = sInputKey.Length.ToString() + "'b" + sInputKey + " : ";
				sOutput = (string)oTruthTable.TruthTableDefinition[sInputKey];
				sVerilog += sOutputVector + " = " + sOutput.Length.ToString() + "'b" + sOutput + ";"; 
				ComponentVerilog.WriteVerilogText(sVerilog,3);				
			}

			if (oTruthTable.DefaultOutput != "")
			{
				sOutput = oTruthTable.DefaultOutput;
				sVerilog = "default : " + sOutputVector + " = " + sOutput.Length.ToString() + "'b" + sOutput + ";"; 
				ComponentVerilog.WriteVerilogText(sVerilog,3);				
			}

			ComponentVerilog.WriteVerilogText("endcase",1);
			ComponentVerilog.WriteVerilogText("end");
		}

		public override void CalculateOutput()
		{
			string sInput = Conversion.NodeVectorsToString(this.SinkNodeVectors);
			string sOutput = oTruthTable.Decode(sInput);
			Conversion.AssignNodeVectorsFromString(this.SourceNodeVectors,sOutput);
		}

	}
}
